

import zlib
import sqlite3 as lite
from dexen.system.server import db
from dexen.system.common.meta import JobMeta
from dexen.system.common.base import Individual


ZIP_NAME = "job_def.zip"
SCHEMA_NAME = "job_def"


class ArchiveMgr(object):
    def __init__(self, job_meta):
        assert isinstance(job_meta, JobMeta)
        self.job_meta = job_meta
        self._archive_job()

    @property
    def job_id(self):
        return self.job_meta.get_id()
    
    @property
    def conn(self):
        return db.get_connection()
    
    def commit(self):
        self.conn.commit()
    
    def _execute_stmt(self, stmt, params):
        cursor = self.conn.cursor()
        cursor.execute(stmt, params)
        cursor.close()

    def _execute_query(self, query, params=None):
        cursor = self.conn.cursor()
        assert isinstance(cursor, lite.Cursor)
        if params is not None:
            cursor.execute(query, params)
        else:
            cursor.execute(query)
        res = cursor.fetchall()
        cursor.close()
        return res

    def _archive_job(self):
        jm = self.job_meta
        assert isinstance(jm, JobMeta)
        stmt = "INSERT INTO Job VALUES (?,?,?,?)"
        params = (jm.get_id(), jm.get_name(), jm.creation_time, jm.get_zip())
        self._execute_stmt(stmt, params)
        self.commit()

    def _archive_ind(self, ind):
        assert isinstance(ind, Individual)
        archived = ind._get_archived()
        for filename, content in archived.items():
            stmt = "INSERT INTO Archive VALUES (?,?,?,?)"
            params = (ind.__id__, filename, buffer(zlib.compress(content)), self.job_id) 
            self._execute_stmt(stmt, params)
        ind._strip_archived() # TODO: Important
    
    def archive_inds(self, inds):
        for ind in inds:
            self._archive_ind(ind)
        self.commit()

    def archive_master(self, archived):
        pass

    def delete_actions(self):
        stmt = "DELETE FROM Action WHERE JobId = ? "
        params = (self.job_id,)
        self._execute_stmt(stmt, params)

    def delete_archives(self):
        stmt = "DELETE FROM Archive WHERE JobId = ?"
        params = (self.job_id, )
        self._execute_stmt(stmt, params)

    def delete_job(self):
        stmt = "DELETE FROM Job WHERE Id = ?"
        params = (self.job_id,)
        self._execute_stmt(stmt, params)

    def get_ind_archive(self, ind_id, name):
        query = """SELECT Content FROM Archive, Job WHERE IndId = ? AND 
                Archive.Name = ? AND Archive.JobId = ? AND Job.Id = ?"""
        params = (ind_id, name, self.job_id, self.job_id)
        rows = self._execute_query(query, params)
        assert len(rows) == 1 
        return str(rows[0]['Content'])
    
    def get_ind_archive_all(self, ind_id):
        query = """SELECT Archive.Name, Content FROM Archive, Job WHERE 
                IndId = ? AND Archive.JobId = ? AND Job.Id = ?"""
        params = (ind_id, self.job_id, self.job_id)
        rows = self._execute_query(query, params)
        res = {}
        for row in rows:
            res[row['Name']] = str(row['Content'])
        return res
    
    def get_ind_archive_names(self, ind_id):
        query = """SELECT Archive.Name FROM Archive, Job WHERE IndId = ? 
                AND Archive.JobId = ? AND Job.Id = ?"""
        params = (ind_id, self.job_id, self.job_id)
        rows = self._execute_query(query, params)
        res = [x['Name'] for x in rows]
        return res
    
    def get_archives_in_batch(self, archives_info_list, batch_size):
        batch_size = batch_size * 1000 # convert KB to bytes
        cur_size = 0
        res = []
        for archive_info in archives_info_list:
            ind_id = archive_info["ind_id"]
            archive_names = self.get_ind_archive_names(ind_id)
            item = {"ind_id" : ind_id, "archives" : {} }
            for name in archive_names:
                if name not in archive_info["archives"]:
                    content = self.get_ind_archive(ind_id, name)
                    item["archives"][name] = content
                    cur_size += len(content)
                    if cur_size >= batch_size:
                        break
            if len(item["archives"].keys()) > 0:
                res.append(item)
            if cur_size >= batch_size:
                break
        return res
        
    def delete_all(self):
        #The method is called, when the corresponding job is deleted by the user.
        self.delete_actions()
        self.delete_archives()
        self.delete_job()
        self.commit()


#===============================================================================
# TESTING
#===============================================================================
def test():
    schema_meta = JobMeta(None, "HAHA")
    arc_mgr = ArchiveMgr(schema_meta)
    ind = Individual()
    ind.__id__ = 1560
    ind.archive_data("ali.txt", range(25))
    ind.archive_data("veli.txt", "Nasilsin koc hahahahahaha")
    arc_mgr.archive_data(ind)

def main():
    test()

if __name__ == "__main__":
    main()

